/*
This file is part of MMM.

MMM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

MMM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with MMM.  If not, see <http://www.gnu.org/licenses/>.
*
* @package    MMM
* @author     Nikolaus Vahrenkamp
* @copyright  2013 High Performance Humanoid Technologies (H2T), Karlsruhe, Germany
*
*/

#ifndef __MMM_LegacyMotionReaderXML_H_
#define __MMM_LegacyMotionReaderXML_H_

#include "../../MMMCore.h"
#include "../../MMMImportExport.h"
#include "LegacyMotion.h"
#include "MotionFrame.h"

#include <Eigen/Core>
#include <string> 
#include <vector>
#include <map>
#include <boost/enable_shared_from_this.hpp>

// using forward declarations here, so that the rapidXML header does not have to be parsed when this file is included
namespace rapidxml
{
	template<class Ch>
	class xml_node;
}

namespace MMM
{

/*! 
    \brief Use this interface to register custom Motion XML tags.
    To be used for tags within a <Motion> ... </Motion> structure.
	\see \ref mmm-extension-motion

*/
class MMM_IMPORT_EXPORT XMLMotionTagProcessor
{
public:
    //! Derived classes must implement this factory method
    virtual bool processMotionXMLTag(rapidxml::xml_node<char>* tag, LegacyMotionPtr motion ) = 0;
};
typedef boost::shared_ptr<XMLMotionTagProcessor> XMLMotionTagProcessorPtr;

/*! 
	\brief Use this interface to register custom motion-data XML tags.
    To be used for tags within a <MotionFrame> ... </MotionFrame> structure.
	\see \ref mmm-extension-motion-data
*/
class MMM_IMPORT_EXPORT XMLMotionFrameTagProcessor
{
public:
    //! Derived classes must implement this factory method
	virtual bool processMotionFrameXMLTag(rapidxml::xml_node<char>* tag, MotionFramePtr motionframe ) = 0;
};
typedef boost::shared_ptr<XMLMotionFrameTagProcessor> XMLMotionFrameTagProcessorPtr;

/*!
    \brief The generic XML reader for legacy MMM motions.
    The following XML tags are initially supported by this reader: "comments", "description","joint_order","motion".
	Custom tag processors can be registered in order to read other data.
    Unknown tags are ignored by default.
    \see XMLTagProcessor
    \see XMLMotionFrameTagProcessor
*/
class MMM_IMPORT_EXPORT LegacyMotionReaderXML : public XMLMotionTagProcessor, public XMLMotionFrameTagProcessor, public boost::enable_shared_from_this<LegacyMotionReaderXML>
{
public:
	EIGEN_MAKE_ALIGNED_OPERATOR_NEW

    LegacyMotionReaderXML();

	/*! Load XML data.
        @param xmlFile The xmlFile path.
        @param motionName The name of the motion. If empty the first motion is selected.
    */
    LegacyMotionPtr loadMotion(const std::string &xmlFile, const std::string &motionName = std::string());
    LegacyMotionList loadAllMotions(const std::string &xmlFile);
    LegacyMotionList loadAllMotionsFromString(const std::string &xmlDataString);

    std::vector<std::string> getMotionNames(const std::string &xmlFile) const;

    /*! 
        Register factory methods for processing custom Motion XML tags.
        \param xmlTag The string that identifies this custom tag. Existing tag processors that are already registered with this name are overwritten.
        \param processor The factory that will create MotionEntry objects.
        \return True on success.
    */
    bool registerMotionXMLTag(const std::string &xmlTag, XMLMotionTagProcessorPtr processor);

    /*! 
        Register factory methods for processing custom MotionFrame XML tags.
        \param xmlTag The string that identifies this custom tag. Existing tag processors that are already registered with this name are overwritten.
        \param processor The factory that will create MotionFrameEntry objects.
        \return True on success.
    */
	bool registerMotionFrameXMLTag(const std::string &xmlTag, XMLMotionFrameTagProcessorPtr processor);


	/*!
        Parse the XML string and generate motion. A complete XML string is expected e.g <MMM><Motion> ... </Motion></MMM>
        In case an error was detected, an empty LegacyMotionPtr is returned.
        @param motionName The name of the motion. If empty, the first motion is used.
	*/
    LegacyMotionPtr createMotionFromString(const std::string &xmlString, const std::string &motionName = std::string(), const std::string &motionFilePath = std::string());
	
	//! Implement the XMLTagProcessor method in order to process the standard MMM tags
    virtual bool processMotionXMLTag(rapidxml::xml_node<char>* tag, LegacyMotionPtr motion );

	//! Implement the XMLMotionFrameTagProcessor method in order to process the standard motion-data tags
	virtual bool processMotionFrameXMLTag(rapidxml::xml_node<char>* tag, MotionFramePtr motionframe );


    std::vector<std::string> getMotionNamesFromXMLString(std::string motionXML) const;
protected:
    bool registerMotionXMLTag(const std::string &xmlTag, XMLMotionTagProcessor *processor);
	bool registerMotionFrameXMLTag(const std::string &xmlTag, XMLMotionFrameTagProcessor *processor);

    bool processMotionFramesTag(rapidxml::xml_node<char>* tag, LegacyMotionPtr motion);
    bool processMotionFrameTag(rapidxml::xml_node<char>* tag, LegacyMotionPtr motion);

    bool processJointOrderTag(rapidxml::xml_node<char>* tag, LegacyMotionPtr motion);

    bool processModelProcessorConfigTag(rapidxml::xml_node<char>* tag, LegacyMotionPtr motion);
    bool processModelTag(rapidxml::xml_node<char>* tag, LegacyMotionPtr motion);
    bool processCommentsTag(rapidxml::xml_node<char>* tag, LegacyMotionPtr motion);
    std::map<std::string, XMLMotionTagProcessor*> xmlProcessors;
	std::map<std::string, XMLMotionFrameTagProcessor*> xmlProcessorsMotionFrame;
    std::vector<XMLMotionTagProcessorPtr> processorList;
	std::vector<XMLMotionFrameTagProcessorPtr> processorListMotionFrame;
};

typedef boost::shared_ptr<LegacyMotionReaderXML> LegacyMotionReaderXMLPtr;

}

#endif 
